home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Environments / Oberon⁄F™ 1.2 / Preinstalled version / Form / Mod / Controllers / Controllers (.txt)
Encoding:
Oberon Document  |  1996-03-29  |  23.9 KB  |  696 lines  |  [oODC/obnF]

  1. Documents.StdDocumentDesc
  2. Documents.DocumentDesc
  3. Containers.ViewDesc
  4. Views.ViewDesc
  5. Stores.StoreDesc
  6. Documents.ModelDesc
  7. Containers.ModelDesc
  8. Models.ModelDesc
  9. Stores.ElemDesc
  10. TextViews.StdViewDesc
  11. TextViews.ViewDesc
  12. TextModels.StdModelDesc
  13. TextModels.ModelDesc
  14. TextModels.AttributesDesc
  15. Geneva
  16. Geneva
  17. Geneva
  18. Geneva
  19. Geneva
  20. MODULE FormControllers;
  21. (* OmInc 
  22.     IMPORT
  23.         Domains, Ports, Stores, Models, Views, Controllers, Properties, Dialog, Containers,
  24.         FormModels, FormViews;
  25.     CONST
  26.         noSelection* = Containers.noSelection; noFocus* = Containers.noFocus;
  27.         tab = 09X; ltab = 0AX; rdel = 7X; ldel = 8X; line = 0DX; esc = 1BX;
  28.         arrowLeft = 1CX; arrowRight = 1DX; arrowUp = 1EX; arrowDown = 1FX;
  29.         (* range of currently supported versions *)
  30.         minVersion = 0; maxBaseVersion = 0; maxStdVersion = 0;
  31.     TYPE
  32.         Controller* = POINTER TO ControllerDesc;
  33.         ControllerDesc* = RECORD (Containers.ControllerDesc)
  34.             form-: FormModels.Model;
  35.             view-: FormViews.View
  36.         END;
  37.         Directory* = POINTER TO DirectoryDesc;
  38.         DirectoryDesc* = RECORD (Containers.DirectoryDesc) END;
  39.         List* = POINTER TO ListDesc;
  40.         ListDesc* = RECORD
  41.             next*: List;
  42.             view*: Views.View
  43.         END;
  44.         StdController = POINTER TO StdControllerDesc;
  45.         StdControllerDesc = RECORD (ControllerDesc)
  46.             sel: List;    (* (sel = NIL) OR (c.ThisFocus() = NIL) *)
  47.             reader: FormModels.Reader;
  48.             lastX, lastY: LONGINT
  49.         END;
  50.         StdDirectory = POINTER TO StdDirectoryDesc;
  51.         StdDirectoryDesc = RECORD (DirectoryDesc) END;
  52.         MarkMsg = RECORD (Views.Message)
  53.             list: List;
  54.             show: BOOLEAN
  55.         END;
  56.     VAR dir-, stdDir-: Directory;
  57.     (** Controller **)
  58.     PROCEDURE (c: Controller) Internalize* (VAR rd: Stores.Reader);
  59.         VAR tag, thisVersion: SHORTINT;
  60.     BEGIN
  61.         c.Internalize^(rd);
  62.         IF rd.cancelled THEN RETURN END;
  63.         rd.ReadVersion(minVersion, maxBaseVersion, thisVersion)
  64.     END Internalize;
  65.     PROCEDURE (c: Controller) Externalize* (VAR wr: Stores.Writer);
  66.     BEGIN
  67.         c.Externalize^(wr);
  68.         wr.WriteVersion(maxBaseVersion)
  69.     END Externalize;
  70.     PROCEDURE (c: Controller) InitView* (view: Views.View);
  71.         VAR v: FormViews.View;
  72.     BEGIN
  73.         c.InitView^(view);
  74.         IF view # NIL THEN
  75.             ASSERT(view IS FormViews.View, 25);
  76.             c.view := view(FormViews.View); c.form := c.view.ThisModel()
  77.         ELSE
  78.             c.form := NIL; c.view := NIL
  79.         END
  80.     END InitView;
  81.     PROCEDURE (c: Controller) ThisView* (): FormViews.View;
  82.     BEGIN
  83.         RETURN c.view
  84.     END ThisView;
  85.     PROCEDURE (c: Controller) Select* (view: Views.View);
  86.     BEGIN
  87.         HALT(127)
  88.     END Select;
  89.     PROCEDURE (c: Controller) Deselect* (view: Views.View);
  90.     BEGIN
  91.         HALT(127)
  92.     END Deselect;
  93.     PROCEDURE (c: Controller) IsSelected* (view: Views.View): BOOLEAN;
  94.     BEGIN
  95.         HALT(127)
  96.     END IsSelected;
  97.     PROCEDURE (c: Controller) GetSelection* (): List;
  98.     BEGIN
  99.         HALT(127)
  100.     END GetSelection;
  101.     PROCEDURE (c: Controller) SetSelection* (l: List);
  102.     BEGIN
  103.         HALT(127)
  104.     END SetSelection;
  105.     (** Directory **)
  106.     PROCEDURE (d: Directory) NewView* (f: FormModels.Model; opts: SET): FormViews.View;
  107.     BEGIN
  108.         HALT(127)
  109.     END NewView;
  110.     (* auxiliary procedures *)
  111.     PROCEDURE MarkList (c: StdController; f: Views.Frame; h: List; show: BOOLEAN);
  112.         VAR l, t, r, b, s: LONGINT;
  113.     BEGIN
  114.         IF (*(f.front OR f.target) &*) ~(Containers.noSelection IN c.opts) THEN
  115.             s := 2 * f.unit;
  116.             WHILE h # NIL DO
  117.                 c.view.GetRect(f, h.view, l, t, r, b);
  118.                 f.MarkRect(l - s, t - s, r + s, b + s, s, Ports.hilite, show);
  119.                 h := h.next
  120.             END
  121.         END
  122.     END MarkList;
  123.     PROCEDURE Toggle (c: StdController; view: Views.View);
  124.     BEGIN
  125.         IF c.IsSelected(view) THEN c.Deselect(view) ELSE c.Select(view) END
  126.     END Toggle;
  127.     (* StdController *)
  128.     PROCEDURE (c: StdController) Internalize (VAR rd: Stores.Reader);
  129.         VAR thisVersion: SHORTINT;
  130.     BEGIN
  131.         c.Internalize^(rd);
  132.         IF rd.cancelled THEN RETURN END;
  133.         rd.ReadVersion(minVersion, maxStdVersion, thisVersion);
  134.         c.sel := NIL; c.lastX := -1
  135.     END Internalize;
  136.     PROCEDURE (c: StdController) Externalize (VAR wr: Stores.Writer);
  137.     BEGIN
  138.         c.Externalize^(wr);
  139.         wr.WriteVersion(maxStdVersion)
  140.     END Externalize;
  141.     PROCEDURE (c: StdController) CopyFrom (source: Controllers.Controller);
  142.     BEGIN
  143.         c.CopyFrom^(source);
  144.         c.sel := NIL; c.lastX := -1
  145.     END CopyFrom;
  146.     PROCEDURE (c: StdController) RestoreMarks (f: Views.Frame; l, t, r, b: LONGINT);
  147.     BEGIN
  148.         IF f.mark THEN
  149.             c.RestoreMarks^(f, l, t, r, b);
  150.             IF (c.lastX <= f.l ) OR (c.lastX >= f.r) OR (c.lastY <= f.t) OR (c.lastY >= f.b) THEN
  151.                 c.lastX := (f.l + f.r) DIV 2; c.lastY := (f.t + f.b) DIV 2
  152.             END
  153.         END
  154.     END RestoreMarks;
  155.     PROCEDURE (c: StdController) HandleViewMsg (f: Views.Frame;
  156.                                                                                 VAR msg: Views.Message);
  157.     BEGIN
  158.         WITH msg: MarkMsg DO
  159.             MarkList(c, f, msg.list, msg.show)
  160.         ELSE
  161.             c.HandleViewMsg^(f, msg)
  162.         END
  163.     END HandleViewMsg;
  164.     (* subclass hooks *)
  165.     PROCEDURE (c: StdController) GetContextType (VAR type: Stores.TypeName);
  166.     BEGIN
  167.         COPY("FormViews.ViewDesc", type)
  168.     END GetContextType;
  169.     PROCEDURE (c: StdController) GetValidOps (VAR valid: SET);
  170.     BEGIN
  171.         valid := {Controllers.pasteChar, Controllers.paste};
  172.         IF c.sel # NIL THEN valid := valid + {Controllers.cut, Controllers.copy} END
  173.     END GetValidOps;
  174.     PROCEDURE (c: StdController) NativeModel (model: Models.Model): BOOLEAN;
  175.     BEGIN
  176.         ASSERT(model # NIL, 20);
  177.         RETURN model IS FormModels.Model
  178.     END NativeModel;
  179.     PROCEDURE (c: StdController) NativeView (view: Views.View): BOOLEAN;
  180.     BEGIN
  181.         ASSERT(view # NIL, 20);
  182.         RETURN view IS FormViews.View
  183.     END NativeView;
  184.     PROCEDURE (c: StdController) NativeCursorAt (f: Views.Frame; x, y: LONGINT): INTEGER;
  185.     BEGIN
  186.         ASSERT(f # NIL, 20);
  187.         RETURN Ports.graphicsCursor
  188.     END NativeCursorAt;
  189.     PROCEDURE (c: StdController) GetFirstView (selection: BOOLEAN; VAR v: Views.View);
  190.         VAR r: FormModels.Reader;
  191.     BEGIN
  192.         IF selection THEN
  193.             IF c.sel # NIL THEN v := c.sel.view ELSE v := NIL END
  194.         ELSE
  195.             r := c.form.NewReader(c.reader); c.reader := r;
  196.             r.Set(NIL); r.ReadView(v)
  197.         END
  198.     END GetFirstView;
  199.     PROCEDURE (c: StdController) GetNextView (selection: BOOLEAN; VAR v: Views.View);
  200.         VAR h: List; r: FormModels.Reader;
  201.     BEGIN    (* could be optimized *)
  202.         ASSERT(v # NIL, 20);
  203.         IF selection THEN
  204.             h := c.sel; WHILE (h # NIL) & (h.view # v) DO h := h.next END; ASSERT(h # NIL, 21);
  205.             IF h.next # NIL THEN v := h.next.view ELSE v := NIL END
  206.         ELSE
  207.             r := c.form.NewReader(c.reader); c.reader := r;
  208.             r.Set(v); r.ReadView(v)
  209.         END
  210.     END GetNextView;
  211.     PROCEDURE (c: StdController) GetSelectionBounds* (f: Views.Frame; VAR x, y, w, h: LONGINT);
  212.         VAR sel: List; l, t, r, b, gw, gh: LONGINT; g: Views.Frame;
  213.     BEGIN
  214.         IF c.Singleton() # NIL THEN
  215.             c.GetSelectionBounds^(f, x, y, w, h)
  216.         ELSE
  217.             l := MAX(LONGINT); t := MAX(LONGINT); r := MIN(LONGINT); b := MIN(LONGINT);
  218.             sel := c.sel;
  219.             WHILE sel # NIL DO
  220.                 g := Views.ThisFrame(f, sel.view);
  221.                 IF g # NIL THEN
  222.                     sel.view.context.GetSize(gw, gh);
  223.                     IF g.gx < l THEN l := g.gx END;
  224.                     IF g.gy < t THEN t := g.gy END;
  225.                     IF g.gx + gw > r THEN r := g.gx + gw END;
  226.                     IF g.gy + gh > b THEN b := g.gy + gh END;
  227.                 END;
  228.                 sel := sel.next
  229.             END;
  230.             IF (l < r) & (t < b) THEN
  231.                 x := l - f.gx - c.view.border; y := t - f.gy - c.view.border;
  232.                 w := r - l + 2 * c.view.border; h := b - t + 2 * c.view.border
  233.             ELSE
  234.                 x := 0; y := 0; w := 0; h := 0
  235.             END
  236.         END
  237.     END GetSelectionBounds;
  238.     PROCEDURE (c: StdController) MarkDropTarget (src, dst: Views.Frame;
  239.                                                                             sx, sy, dx, dy, w, h, rx, ry: LONGINT;
  240.                                                                             type: Stores.TypeName;
  241.                                                                             isSingle, show: BOOLEAN);
  242.         CONST dm = 4 * Ports.point; dp = 18 * Ports.point;
  243.         VAR vx, vy, l, t, r, b: LONGINT; sc: Containers.Controller; s: Views.View;
  244.     BEGIN    (* cf. Drop *)
  245.         IF ~isSingle & (src # NIL) & (src.view IS FormViews.View) THEN
  246.             vx := dx - sx; vy := dy - sy;
  247.             sc := src.view(FormViews.View).ThisController();
  248.             IF sc # NIL THEN
  249.                 WITH sc: Controller DO
  250.                     sc.GetFirstView(Containers.selection, s);
  251.                     WHILE s # NIL DO
  252.                         FormModels.GetRect(s, l, t, r, b); w := r - l; h := b - t;
  253.                         INC(l, vx); INC(t, vy); FormViews.RoundToGrid(c.view, l, t);
  254.                         dst.MarkRect(l, t, l + w, t + h, 0, Ports.invert, show);
  255.                         sc.GetNextView(Containers.selection, s)
  256.                     END
  257.                 END
  258.             END
  259.         ELSIF (w > 0) & (h > 0) THEN
  260.             FormViews.RoundToGrid(c.view, dx, dy);
  261.             vx := dx - rx; vy := dy - ry;
  262.             IF ~isSingle & (type = "FormViews.StdViewDesc") THEN
  263.                 dst.MarkRect(vx - dm, vy, vx + dp, vy + dst.unit, 0, Ports.invert, show);
  264.                 dst.MarkRect(vx, vy - dm, vx + dst.unit, vy + dp, 0, Ports.invert, show);
  265.                 INC(vx, w); INC(vy, h);
  266.                 dst.MarkRect(vx - dp, vy, vx + dm, vy + dst.unit, 0, Ports.invert, show);
  267.                 dst.MarkRect(vx, vy - dp, vx + dst.unit, vy + dm, 0, Ports.invert, show)
  268.             ELSE
  269.                 dst.MarkRect(vx, vy, vx + w, vy + h, 0, Ports.invert, show)
  270.             END
  271.         ELSE
  272.             FormViews.RoundToGrid(c.view, dx, dy);
  273.             dst.MarkRect(dx - dm, dy, dx + dp, dy + dst.unit, 0, Ports.invert, show);
  274.             dst.MarkRect(dx, dy - dm, dx + dst.unit, dy + dp, 0, Ports.invert, show)
  275.         END
  276.     END MarkDropTarget;
  277.     PROCEDURE (c: StdController) TrackMarks (f: Views.Frame; x, y: LONGINT;
  278.                                                                             units, extend, add: BOOLEAN);
  279.         VAR dx, dy, x0, y0, dx0, dy0: LONGINT; isDown: BOOLEAN; h: Views.View; m: SET;
  280.         PROCEDURE InvertRect (f: Views.Frame; x, y, dx, dy: LONGINT);
  281.             VAR l, t, r, b: LONGINT;
  282.         BEGIN
  283.             IF dx >= 0 THEN l := x; r := x + dx ELSE l := x + dx; r := x END;
  284.             IF dy >= 0 THEN t := y; b := y + dy ELSE t := y + dy; b := y END;
  285.             f.MarkRect(l, t, r, b, 0, Ports.dim50, TRUE)
  286.         END InvertRect;
  287.         PROCEDURE SelectArea (c: StdController; l, t, r, b: LONGINT; toggle: BOOLEAN);
  288.             VAR h: LONGINT; s: FormModels.Reader; v: Views.View; p, q: List; empty: BOOLEAN;
  289.         BEGIN
  290.             IF l > r THEN h := l; l := r; r := h END;
  291.             IF t > b THEN h := t; t := b; b := h END;
  292.             s := c.form.NewReader(c.reader); c.reader := s;
  293.             s.Set(NIL); s.ReadView(v); p := NIL; empty := c.sel = NIL;
  294.             WHILE v # NIL DO
  295.                 IF (s.l < r) & (s.t < b) & (s.r > l) & (s.b > t) THEN
  296.                     IF toggle THEN Toggle(c, v)
  297.                     ELSIF ~empty THEN c.Select(v)
  298.                     ELSE NEW(q); q.next := p; p := q; q.view := v
  299.                     END
  300.                 END;
  301.                 s.ReadView(v)
  302.             END;
  303.             (* this optimization prevents the appearance of a temporary singleton *)
  304.             IF ~toggle & empty THEN c.SetSelection(p) END
  305.         END SelectArea;
  306.     BEGIN
  307.         dx := 0; dy := 0;    (* vector from (x, y) *)
  308.         InvertRect(f, x, y, dx, dy);
  309.         REPEAT
  310.             f.Input(x0, y0, m, isDown);
  311.             dx0 := x0 - x; dy0 := y0 - y;
  312.             IF (dx0 # dx) OR (dy0 # dy) THEN
  313.                 InvertRect(f, x, y, dx, dy);
  314.                 dx := dx0; dy := dy0;
  315.                 InvertRect(f, x, y, dx, dy)
  316.             END
  317.         UNTIL ~isDown;
  318.         InvertRect(f, x, y, dx, dy);
  319.         c.lastX := x0; c.lastY := y0;
  320.         IF (dx # 0) OR (dy # 0) THEN
  321.             SelectArea(c, x, y, x + dx, y + dy, extend OR add)
  322.         ELSE
  323.             h := c.form.ViewAt(x, y);
  324.             IF h # NIL THEN
  325.                 IF extend OR add THEN Toggle(c, h) ELSE c.Select(h) END
  326.             END
  327.         END
  328.     END TrackMarks;
  329.     PROCEDURE (c: StdController) Resize (view: Views.View; l, t, r, b: LONGINT);
  330.     BEGIN
  331.         c.form.Resize(view, l, t, r, b)
  332.     END Resize;
  333.     PROCEDURE (c: StdController) DeleteSelection;
  334.         VAR script: Domains.Operation; h: List;
  335.     BEGIN
  336.         Models.BeginScript(c.form, "#System:Deletion", script);
  337.         h := c.sel; WHILE h # NIL DO c.form.Delete(h.view); h := h.next END;
  338.         Models.EndScript(c.form, script)
  339.     END DeleteSelection;
  340.     PROCEDURE (c: StdController) MoveLocalSelection (src, dst: Views.Frame; sx, sy,
  341.                                                                                         dx, dy: LONGINT);
  342.             VAR script: Domains.Operation; sel, h: List;
  343.     BEGIN
  344.         dx := dx - sx; dy := dy - sy;
  345.         IF (dx # 0) OR (dy # 0) THEN
  346.             FormViews.RoundToGrid(c.view, dx, dy);
  347.             sel := c.GetSelection();
  348.             Models.BeginScript(c.form, "#System:Moving", script);
  349.             h := sel; WHILE h # NIL DO c.form.Move(h.view, dx, dy); h := h.next END;
  350.             Models.EndScript(c.form, script);
  351.             c.SetSelection(sel)
  352.         END
  353.     END MoveLocalSelection;
  354.     PROCEDURE (c: StdController) CopyLocalSelection (src, dst: Views.Frame; sx, sy,
  355.                                                                                         dx, dy: LONGINT);
  356.         VAR script: Domains.Operation; q: Views.View; h, s, t: List;
  357.     BEGIN
  358.         dx := dx - sx; dy := dy - sy;
  359.         IF (dx # 0) OR (dy # 0) THEN
  360.             FormViews.RoundToGrid(c.view, dx, dy);
  361.             Models.BeginScript(c.form, "#System:Copying", script);
  362.             h := c.GetSelection(); s := NIL;
  363.             WHILE h # NIL DO
  364.                 q := h.view; c.form.Copy(q, dx, dy);
  365.                 NEW(t); t.next := s; s := t; t.view := q;
  366.                 h := h.next
  367.             END;
  368.             Models.EndScript(c.form, script);
  369.             c.SetSelection(s)
  370.         END
  371.     END CopyLocalSelection;
  372.     PROCEDURE (c: StdController) SelectionCopy (): Containers.Model;
  373.         VAR f: FormModels.Model; p: List; w, h, dx, dy, l, t, r, b: LONGINT; st: Stores.Store;
  374.         PROCEDURE GetOffset (f: FormModels.Model; p: List; border: LONGINT; VAR dx, dy: LONGINT);
  375.             VAR l, t, vl, vt, vr, vb: LONGINT;
  376.         BEGIN
  377.             IF p # NIL THEN
  378.                 l := MAX(LONGINT); t := MAX(LONGINT);
  379.                 WHILE p # NIL DO
  380.                     FormModels.GetRect(p.view, vl, vt, vr, vb);
  381.                     IF vl < l THEN l := vl END;
  382.                     IF vt < t THEN t := vt END;
  383.                     p := p.next
  384.                 END;
  385.                 dx := l - border; dy := t - border
  386.             END
  387.         END GetOffset;
  388.     BEGIN
  389.         st := Stores.Clone(c.form); f := st(FormModels.Model);
  390.         p := c.sel;
  391.         GetOffset(c.form, p, c.view.border, dx, dy);
  392.         WHILE p # NIL DO
  393.             FormModels.GetRect(p.view, l, t, r, b);
  394.             f.Insert(Views.CopyOf(p.view, Views.deep), l - dx, t - dy, r - dx, b - dy);
  395.             p := p.next
  396.         END;
  397.         RETURN f
  398.     END SelectionCopy;
  399.     PROCEDURE (c: StdController) NativePaste (m: Models.Model; f: Views.Frame);
  400.         VAR x, y, cw, ch, l, t, r, b: LONGINT; p: Views.View; s: FormModels.Reader;
  401.             n, i: INTEGER;
  402.     BEGIN
  403.         x := c.lastX; y := c.lastY;
  404.         c.view.context.GetSize(cw, ch);
  405.         IF (x <= f.l) OR (x >= f.r) OR (y <= f.t) OR (y >= f.b) THEN
  406.             x := (f.l + f.r) DIV 2; y := (f.r + f.b) DIV 2
  407.         END;
  408.         c.lastX := x; c.lastY := y;
  409.         FormViews.RoundToGrid(c.view, x, y);
  410.         WITH m: FormModels.Model DO
  411.             s := m.NewReader(NIL);
  412.             s.Set(NIL); s.ReadView(p); n := 0;
  413.             WHILE p # NIL DO
  414.                 FormModels.GetRect(p, l, t, r, b);
  415.                 c.form.Insert(Views.CopyOf(p, Views.shallow), x + l, y + t, x + r, y + b); INC(n);
  416.                 s.ReadView(p)
  417.             END;
  418.             (* n views have been inserted at the top => select them *)
  419.             c.SelectAll(Containers.deselect);
  420.             i := c.form.NofViews() - n; ASSERT(i >= 0, 100);
  421.             s := c.form.NewReader(s);
  422.             s.Set(NIL); WHILE i # 0 DO s.ReadView(p); DEC(i) END;    (* skip old views *)
  423.             WHILE n # 0 DO s.ReadView(p); c.Select(p); DEC(n) END
  424.         END
  425.     END NativePaste;
  426.     PROCEDURE (c: StdController) ArrowChar (f: Views.Frame; ch: CHAR; units,  select: BOOLEAN);
  427.         VAR d: LONGINT;
  428.     BEGIN
  429.         d := c.view.grid;
  430.         IF units THEN d := d * c.view.gridFactor END;
  431.         IF ch = arrowLeft THEN
  432.             c.MoveLocalSelection(f, f, 0, 0, -d, 0)
  433.         ELSIF ch = arrowRight THEN
  434.             c.MoveLocalSelection(f, f, 0, 0, +d, 0)
  435.         ELSIF ch = arrowUp THEN
  436.             c.MoveLocalSelection(f, f, 0, 0, 0, -d)
  437.         ELSIF ch = arrowDown THEN
  438.             c.MoveLocalSelection(f, f, 0, 0, 0, +d)
  439.         END
  440.     END ArrowChar;
  441.     PROCEDURE (c: StdController) ControlChar (f: Views.Frame; ch: CHAR);
  442.     BEGIN
  443.         IF (ch = ldel) OR (ch = rdel) THEN c.DeleteSelection END
  444.     END ControlChar;
  445.     PROCEDURE (c: StdController) PasteChar (ch: CHAR);
  446.     END PasteChar;
  447.     PROCEDURE (c: StdController) PasteLChar (ch: Containers.LONGCHAR);
  448.     END PasteLChar;
  449.     PROCEDURE (c: StdController) PasteView (f: Views.Frame; v: Views.View;
  450.                                                                             w, h: LONGINT);
  451.         VAR minW, maxW, minH, maxH, x, y: LONGINT;
  452.     BEGIN
  453.         x := c.lastX; y := c.lastY;
  454.         IF (x <= f.l) OR (x >= f.r) OR (y <= f.t) OR (y >= f.b) THEN
  455.             x := (f.l + f.r) DIV 2; y := (f.t + f.b) DIV 2
  456.         END;
  457.         c.lastX := x; c.lastY := y;
  458.         FormViews.RoundToGrid(c.view, x, y);
  459.         c.form.GetEmbeddingLimits(minW, maxW, minH, maxH);
  460.         Properties.PreferredSize(v, minW, maxW, minH, maxH, minW, minH, w, h);
  461.         c.form.Insert(v, x, y, x + w, y + h); c.Select(v)
  462.     END PasteView;
  463.     PROCEDURE (c: StdController) Drop (src, dst: Views.Frame; sx, sy, dx, dy,
  464.                                                             w, h, rx, ry: LONGINT; v: Views.View; isSingle: BOOLEAN);
  465.         VAR minW, maxW, minH, maxH, vx, vy, l, t, r, b, sw, sh: LONGINT;
  466.             sc: Containers.Controller; s: Views.View; p, q: List;
  467.             rd: FormModels.Reader; m: FormModels.Model;
  468.     BEGIN    (* cf. MarkDropTarget *)
  469.         DEC(dx, rx); DEC(dy, ry);
  470.         IF ~isSingle & (v IS FormViews.View) THEN
  471.             m := v(FormViews.View).ThisModel();
  472.             rd := m.NewReader(NIL);
  473.             rd.ReadView(s); p := NIL;
  474.             WHILE s # NIL DO
  475.                 l := rd.l + dx; t := rd.t + dy; sw := rd.r - rd.l; sh := rd.b - rd.t;
  476.                 FormViews.RoundToGrid(c.view, l, t);
  477.                 s := Views.CopyOf(s, Views.shallow);
  478.                 c.form.Insert(s, l, t, l + sw, t + sh);
  479.                 NEW(q); q.next := p; p := q; q.view := s;
  480.                 rd.ReadView(s)
  481.             END;
  482.             c.SetSelection(p)
  483.         ELSE
  484.             FormViews.RoundToGrid(c.view, dx, dy);
  485.             c.form.GetEmbeddingLimits(minW, maxW, minH, maxH);
  486.             Properties.PreferredSize(v, minW, maxW, minH, maxH, minW, minH, w, h);
  487.             c.form.Insert(v, dx, dy, dx + w, dy + h); c.Select(v)
  488.         END
  489.     END Drop;
  490.     (* selection *)
  491.     PROCEDURE (c: StdController) HasSelection (): BOOLEAN;
  492.     BEGIN
  493.         RETURN c.sel # NIL
  494.     END HasSelection;
  495.     PROCEDURE (c: StdController) Selectable (): BOOLEAN;
  496.     BEGIN
  497.         RETURN c.form.NofViews() # 0
  498.     END Selectable;
  499.     PROCEDURE (c: StdController) SetSingleton (s: Views.View);
  500.         VAR l: List;
  501.     BEGIN
  502.         c.SetSingleton^(s);
  503.         IF s # NIL THEN NEW(l); l.view := s; c.sel := l ELSE c.sel := NIL END
  504.     END SetSingleton;
  505.     PROCEDURE (c: StdController) SelectAll (select: BOOLEAN);
  506.         VAR s: FormModels.Reader; v: Views.View; l, h: List; msg: MarkMsg;
  507.     BEGIN
  508.         IF select THEN
  509.             ASSERT(~(Containers.noSelection IN c.opts), 20);
  510.             c.SetFocus(NIL);
  511.             s := c.form.NewReader(c.reader); c.reader := s;
  512.             s.Set(NIL); s.ReadView(v);
  513.             IF c.form.NofViews() = 1 THEN
  514.                 ASSERT(v # NIL, 100);
  515.                 c.SetSingleton(v)
  516.             ELSE
  517.                 IF (c.sel # NIL) & (c.sel.next = NIL) THEN c.SetSingleton(NIL) END;
  518.                 l := NIL;
  519.                 WHILE v # NIL DO
  520.                     IF ~c.IsSelected(v) THEN NEW(h); h.next := l; l := h; h.view := v END;
  521.                     s.ReadView(v)
  522.                 END;
  523.                 msg.list := l;
  524.                 h := c.sel; WHILE (h # NIL) & (h.next # NIL) DO h := h.next END;
  525.                 IF h = NIL THEN c.sel := l ELSE h.next := l END;
  526.                 IF msg.list # NIL THEN msg.show := TRUE; Views.Broadcast(c.view, msg) END
  527.             END
  528.         ELSIF c.sel # NIL THEN
  529.             IF c.sel.next = NIL THEN    (* singleton *)
  530.                 c.SetSingleton(NIL)
  531.             ELSE
  532.                 msg.list := c.sel; c.sel := NIL; 
  533.                 msg.show := FALSE; Views.Broadcast(c.view, msg)
  534.             END
  535.         END
  536.     END SelectAll;
  537.     PROCEDURE (c: StdController) InSelection (f: Views.Frame; x, y: LONGINT): BOOLEAN;
  538.         VAR g: Views.Frame;
  539.     BEGIN
  540.         g := Views.FrameAt(f, x, y);
  541.         IF g # NIL THEN
  542.             RETURN c.IsSelected(g.view)
  543.         ELSE
  544.             RETURN FALSE
  545.         END
  546.     END InSelection;
  547.     PROCEDURE (c: StdController) MarkSelection (f: Views.Frame; show: BOOLEAN);
  548.     BEGIN
  549.         IF c.sel = NIL THEN    (* skip *)
  550.         ELSIF c.sel.next = NIL THEN
  551.             Containers.MarkSingleton(c, f, show)
  552.         ELSE
  553.             MarkList(c, f, c.sel, show)
  554.         END
  555.     END MarkSelection;
  556.     (* caret *)
  557.     PROCEDURE (c: StdController) HasCaret (): BOOLEAN;
  558.     BEGIN
  559.         RETURN TRUE
  560.     END HasCaret;
  561.     PROCEDURE (c: StdController) MarkCaret (f: Views.Frame; show: BOOLEAN);
  562.     END MarkCaret;
  563.     (* FormController protocol *)
  564.     PROCEDURE (c: StdController) Select (view: Views.View);
  565.         VAR l, h, sel: List; msg: MarkMsg;
  566.     BEGIN
  567.         ASSERT(view # NIL, 20); ASSERT(view.context.ThisModel() = c.form, 21);
  568.         ASSERT(~(Containers.noSelection IN c.opts), 22);
  569.         l := c.sel; WHILE (l # NIL) & (l.view # view) DO l := l.next END;
  570.         IF l = NIL THEN    (* view is not yet selected *)
  571.             sel := c.sel;
  572.             IF sel = NIL THEN
  573.                 c.SetSingleton(view)
  574.             ELSE
  575.                 NEW(l); l.view := view;
  576.                 IF sel.next = NIL THEN
  577.                     c.SetSingleton(NIL); ASSERT(c.sel = NIL, 100);
  578.                     l.next := sel; c.sel := l;
  579.                     msg.list := l
  580.                 ELSE
  581.                     l.next := sel; c.sel := l;
  582.                     NEW(h); h.view := view;
  583.                     msg.list := h
  584.                 END;
  585.                 msg.show := TRUE; Views.Broadcast(c.view, msg)
  586.             END
  587.         END
  588.     END Select;
  589.     PROCEDURE (c: StdController) Deselect (view: Views.View);
  590.         VAR l, h: List; msg: MarkMsg;
  591.     BEGIN
  592.         ASSERT(view # NIL, 20); ASSERT(view.context.ThisModel() = c.form, 21);
  593.         l := c.sel; h := NIL; WHILE (l # NIL) & (l.view # view) DO h := l; l := l.next END;
  594.         IF l # NIL THEN    (* l is selection node of view, h its predecessor *)
  595.             IF (h = NIL) & (l.next = NIL) THEN    (* singleton *)
  596.                 c.SetSingleton(NIL)
  597.             ELSE
  598.                 IF h = NIL THEN c.sel := l.next ELSE h.next := l.next END;
  599.                 msg.list:= l; l.next := NIL; msg.show := FALSE; Views.Broadcast(c.view, msg);
  600.                 IF (c.sel # NIL) & (c.sel.next = NIL) THEN    (* singleton *)
  601.                     view := c.sel.view;
  602.                     msg.list := c.sel; c.sel := NIL; 
  603.                     msg.show := TRUE; Views.Broadcast(c.view, msg);
  604.                     c.SetSingleton(view)
  605.                 END
  606.             END
  607.         END
  608.     END Deselect;
  609.     PROCEDURE (c: StdController) IsSelected (view: Views.View): BOOLEAN;
  610.         VAR l: List;
  611.     BEGIN
  612.         ASSERT(view # NIL, 20); ASSERT(view.context.ThisModel() = c.form, 21);
  613.         l := c.sel; WHILE (l # NIL) & (l.view # view) DO l := l.next END;
  614.         RETURN l # NIL
  615.     END IsSelected;
  616.     PROCEDURE (c: StdController) GetSelection (): List;
  617.         VAR l, h, s: List;
  618.     BEGIN
  619.         l := NIL; s := c.sel;
  620.         WHILE s # NIL DO NEW(h); h.next := l; l := h; h.view := s.view; s := s.next END;
  621.         RETURN l
  622.     END GetSelection;
  623.     PROCEDURE (c: StdController) SetSelection (l: List);
  624.         VAR msg: MarkMsg;
  625.     BEGIN
  626.         c.SelectAll(FALSE); ASSERT(c.sel = NIL, 100);
  627.         IF l = NIL THEN    (* skip *)
  628.         ELSIF l.next = NIL THEN
  629.             c.SetSingleton(l.view)
  630.         ELSE
  631.             msg.list := l; c.sel := l; 
  632.             msg.show := TRUE; Views.Broadcast(c.view, msg)
  633.         END
  634.     END SetSelection;
  635.     (* StdDirectory *)
  636.     PROCEDURE (d: StdDirectory) NewController (opts: SET): Controller;
  637.         VAR c: StdController;
  638.     BEGIN
  639.         NEW(c); c.SetOpts(opts); RETURN c
  640.     END NewController;
  641.     PROCEDURE (d: StdDirectory) NewView (f: FormModels.Model; opts: SET): FormViews.View;
  642.         VAR c: Containers.Controller; v: FormViews.View;
  643.     BEGIN
  644.         v := FormViews.dir.New(f); c := v.ThisController();
  645.         IF c # NIL THEN c.SetOpts(opts) ELSE v.SetController(d.NewController(opts)) END;
  646.         RETURN v
  647.     END NewView;
  648.     (** miscellaneous **)
  649.     PROCEDURE Focus* (): Controller;
  650.         VAR v: Views.View; c: Controllers.Controller;
  651.     BEGIN
  652.         v := Controllers.FocusView();
  653.         IF (v # NIL) & (v IS FormViews.View) THEN
  654.             c := v(FormViews.View).ThisController();
  655.             IF (c # NIL) & (c IS Controller) THEN
  656.                 RETURN c(Controller)
  657.             ELSE RETURN NIL
  658.             END
  659.         ELSE RETURN NIL
  660.         END
  661.     END Focus;
  662.     PROCEDURE Insert* (c: Controller; view: Views.View; l, t, r, b: LONGINT);
  663.         VAR w, h: LONGINT;
  664.     BEGIN
  665.         w := r - l; h := b - t;
  666.         FormViews.RoundToGrid(c.view, l, t);
  667.         c.form.Insert(view, l, t, l + w, t + h)
  668.     END Insert;
  669.     PROCEDURE SetDir* (d: Directory);
  670.     BEGIN
  671.         ASSERT(d # NIL, 20); dir := d
  672.     END SetDir;
  673.     PROCEDURE Install*;
  674.     BEGIN
  675.         FormViews.SetCtrlDir(dir)
  676.     END Install;
  677.     PROCEDURE Init;
  678.         VAR d: StdDirectory;
  679.     BEGIN
  680.         NEW(d); SetDir(d); stdDir := d
  681.     END Init;
  682. BEGIN
  683.     Init
  684. END FormControllers.
  685. TextControllers.StdCtrlDesc
  686. TextControllers.ControllerDesc
  687. Containers.ControllerDesc
  688. Controllers.ControllerDesc
  689. TextRulers.StdRulerDesc
  690. TextRulers.RulerDesc
  691. TextRulers.StdStyleDesc
  692. TextRulers.StyleDesc
  693. TextRulers.AttributesDesc
  694. Helvetica
  695. Documents.ControllerDesc
  696.